import numpy
import png2obj.image
import png2obj.imagedata
import png2obj.mesh
import png2obj.texture_style

def minecraftStyle(name, data, placeholderScale = 4, textureStyle=png2obj.texture_style.ZProjectionStyle):
    data = addBorder(data)
    textureStyle = textureStyle(data)
    nx, ny = data.shape
    mesh = png2obj.mesh.Mesh(name)
    
    # top/bottom faces
    for ix in range(nx):
        zStart = 0.0
        for iy in range(ny):
            x, y = png2obj.mesh.indexToMeshCoord(ix, iy, nx, ny)
            z = data[ix, iy]
            # add face if z is different and nonzero
            if z != zStart and zStart != 0.0:
                posVertices = numpy.array([
                    [x, x+1.0, x+1.0, x],
                    [yStart, yStart, y, y],
                    [zStart, zStart, zStart, zStart]])
                negVertices = negateVertices(posVertices)
                mesh.addFace(posVertices, textureStyle.texCoords(posVertices, 2))
                mesh.addFace(negVertices, textureStyle.texCoords(negVertices, 2))
            # start new face is z is different
            if z != zStart:
                yStart = y
                zStart = z
            
    # faces from edges along x direction
    for ix in range(nx):
        for iy in range(ny-1):
            x, y = png2obj.mesh.indexToMeshCoord(ix, iy+1, nx, ny)
            zneg = data[ix, iy]
            zpos = data[ix, iy+1]
            if zneg == zpos: continue
            posVertices = numpy.array([
                [x+1.0, x+1.0, x, x],
                [y, y, y, y],
                [zneg, zpos, zpos, zneg]])
            negVertices = negateVertices(posVertices)
            mesh.addFace(posVertices, textureStyle.texCoords(posVertices, 1))
            mesh.addFace(negVertices, textureStyle.texCoords(negVertices, 1))
            
    # faces from edges along y direction
    for iy in range(ny):
        for ix in range(nx-1):
            x, y = png2obj.mesh.indexToMeshCoord(ix+1, iy, nx, ny)
            zneg = data[ix, iy]
            zpos = data[ix+1, iy]
            if zneg == zpos: continue
            posVertices = numpy.array([
                [x, x, x, x],
                [y, y, y+1.0, y+1.0],
                [zneg, zpos, zpos, zneg]])
            negVertices = negateVertices(posVertices)
            mesh.addFace(posVertices, textureStyle.texCoords(posVertices, 0))
            mesh.addFace(negVertices, textureStyle.texCoords(negVertices, 0))
    return mesh, textureStyle.placeholderImageData(placeholderScale)

def addBorder(data, width=1):
    nx, ny = data.shape
    result = numpy.zeros((nx+2*width, ny+2*width), float)
    result[width:-width, width:-width] = data
    return result

def negateVertices(vertices):
    result = numpy.copy(vertices[:, ::-1])
    result[2, :] = -result[2, :]
    return result
